package demo.db.tsdb.prometheus;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import demo.java.net.HttpDemo;
import demo.json.fastJson.FastJsonDemo;
import demo.vo.exp.ServiceException;
import demo.vo.http.ResponseVo;
import demo.vo.tsdb.DataPoint;
import demo.vo.tsdb.TsdbData;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GrafanaTest {

    private static Logger logger = LoggerFactory.getLogger(GrafanaTest.class);

    public static final String HOST = "https://grafana.ximalaya.com";

    @Test
    public void testMysqlSlave() {
        long end = System.currentTimeMillis();
        long start = end - 60 * 1000L;
        try {
            List<JSONObject> list = mysqlSlave(start, end);
            list.forEach(System.out::println);
            System.out.println(list.size());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testMysqlSlaveStatusSecondsBehindMaster() {
        long end = System.currentTimeMillis();
        long start = end - 30 * 60 * 1000L;
        String instance = "master8.db:9104";
        try {
            List<TsdbData> list = mysqlSlaveStatusSecondsBehindMaster(instance, start, end, 15);
            list.forEach(System.out::println);
            System.out.println(list.size());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }

    }

    @Test
    public void testRedisUsedCpuUser() {
        long end = System.currentTimeMillis();
        long start = end - 5 * 60 * 1000L;
        String instance = "app6:6379";
        try {
            List<TsdbData> list = redisUsedCpuUserChart(instance, start, end, 15);
            list.forEach(System.out::println);
            list = redisUsedCpuSysChart(instance, start, end, 15);
            list.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }

    /**
     * REDIS CPU使用率：USER
     * 
     * @param instance
     * @param start
     * @param end
     * @param step
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public List<TsdbData> redisUsedCpuUserChart(String instance, long start, long end, int step)
            throws IOException, ServiceException {
        String query = "/api/datasources/proxy/2/api/v1/query_range?start=%s&end=%s&step=%s&query=";
        String metricParam = "irate(redis_used_cpu_user{alias=~\"" + instance + "\"}[1m])";
        String path = String.format(query, start / 1000, end / 1000, step)
                + URLEncoder.encode(metricParam, StandardCharsets.UTF_8.name());
        logger.info("rabbit mq grafana url : {}", path);
        String data = request(path);
        JSONObject json = JSON.parseObject(data);
        if (!json.containsKey("data")) {
            return Collections.emptyList();
        }
        JSONArray resultArray = json.getJSONObject("data").getJSONArray("result");
        if (resultArray == null || resultArray.isEmpty()) {
            return Collections.emptyList();
        }
        List<TsdbData> result = new ArrayList<>(resultArray.size());
        for (int i = 0; i < resultArray.size(); i++) {
            JSONObject element = resultArray.getJSONObject(i);
            Map<String, String> tags = element.getObject("metric", new TypeReference<Map<String, String>>() {
            });
            JSONArray values = element.getJSONArray("values");
            List<DataPoint> dps = new ArrayList<>(values.size());
            for (int j = 0; j < values.size(); j++) {
                JSONArray a = values.getJSONArray(j);
                DataPoint vo = new DataPoint(a.getLongValue(0) * 1000, a.getDoubleValue(1));
                dps.add(vo);
            }
            TsdbData tsdbData = new TsdbData();
            tsdbData.setDps(dps);
            tsdbData.setTags(tags);
            result.add(tsdbData);
        }
        return result;
    }

    /**
     * REDIS CPU使用率 SYS
     * 
     * @param instance
     * @param start
     * @param end
     * @param step
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public List<TsdbData> redisUsedCpuSysChart(String instance, long start, long end, int step)
            throws IOException, ServiceException {
        String query = "/api/datasources/proxy/2/api/v1/query_range?start=%s&end=%s&step=%s&query=";
        String metricParam = "irate(redis_used_cpu_sys{alias=~\"" + instance + "\"}[1m])";
        String path = String.format(query, start / 1000, end / 1000, step)
                + URLEncoder.encode(metricParam, StandardCharsets.UTF_8.name());
        logger.info("rabbit mq grafana url : {}", path);
        String data = request(path);
        JSONObject json = JSON.parseObject(data);
        if (!json.containsKey("data")) {
            return Collections.emptyList();
        }
        JSONArray resultArray = json.getJSONObject("data").getJSONArray("result");
        if (resultArray == null || resultArray.isEmpty()) {
            return Collections.emptyList();
        }
        List<TsdbData> result = new ArrayList<>(resultArray.size());
        for (int i = 0; i < resultArray.size(); i++) {
            JSONObject element = resultArray.getJSONObject(i);
            Map<String, String> tags = element.getObject("metric", new TypeReference<Map<String, String>>() {
            });
            JSONArray values = element.getJSONArray("values");
            List<DataPoint> dps = new ArrayList<>(values.size());
            for (int j = 0; j < values.size(); j++) {
                JSONArray a = values.getJSONArray(j);
                DataPoint vo = new DataPoint(a.getLongValue(0) * 1000, a.getDoubleValue(1));
                dps.add(vo);
            }
            TsdbData tsdbData = new TsdbData();
            tsdbData.setDps(dps);
            tsdbData.setTags(tags);
            result.add(tsdbData);
        }
        return result;
    }

    /**
     * MySQL 主从延迟
     * 
     * @param instance 从库实例
     * @param start
     * @param end
     * @param step
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public List<TsdbData> mysqlSlaveStatusSecondsBehindMaster(String instance, long start, long end, int step)
            throws IOException, ServiceException {
        String query = "/api/datasources/proxy/2/api/v1/query_range?start=%s&end=%s&step=%s&query=";
        String metricParam = "mysql_slave_status_seconds_behind_master{instance=\"" + instance + "\"}";
        String path = String.format(query, start / 1000, end / 1000, step)
                + URLEncoder.encode(metricParam, StandardCharsets.UTF_8.name());
        logger.info("rabbit mq grafana url : {}", path);
        String data = request(path);
        JSONObject json = JSON.parseObject(data);
        FastJsonDemo.prettyPrint(json);
        if (!json.containsKey("data")) {
            return Collections.emptyList();
        }
        JSONArray resultArray = json.getJSONObject("data").getJSONArray("result");
        if (resultArray == null || resultArray.isEmpty()) {
            return Collections.emptyList();
        }
        List<TsdbData> result = new ArrayList<>(resultArray.size());
        for (int i = 0; i < resultArray.size(); i++) {
            JSONObject element = resultArray.getJSONObject(i);
            Map<String, String> tags = element.getObject("metric", new TypeReference<Map<String, String>>() {
            });
            JSONArray values = element.getJSONArray("values");
            List<DataPoint> dps = new ArrayList<>(values.size());
            for (int j = 0; j < values.size(); j++) {
                JSONArray a = values.getJSONArray(j);
                DataPoint vo = new DataPoint(a.getLongValue(0) * 1000, a.getLongValue(1));
                dps.add(vo);
            }
            TsdbData tsdbData = new TsdbData();
            tsdbData.setDps(dps);
            tsdbData.setTags(tags);
            result.add(tsdbData);
        }
        return result;
    }

    /**
     * MYSQL 从库实例
     * 
     * @param start
     * @param end
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    public List<JSONObject> mysqlSlave(long start, long end) throws IOException, ServiceException {
        String path = String.format(
                "/api/datasources/proxy/2/api/v1/series?start=%s&end=%s&match[]=mysql_slave_status_seconds_behind_master",
                start / 1000, end / 1000);
        String str = request(path);
        JSONObject json = JSON.parseObject(str);
        FastJsonDemo.prettyPrint(json);
        JSONArray jsonArray = json.getJSONArray("data");
        if (jsonArray == null || jsonArray.isEmpty()) {
            return Collections.emptyList();
        }
        return (List<JSONObject>) jsonArray.stream()
                .map(e -> ((JSONObject) e))
                .collect(Collectors.toList());
    }

    /**
     * 组装HOST 和 path ，添加用户名密码信息，发送请求
     * 
     * @param path
     * @return
     * @throws IOException
     * @throws ServiceException
     */
    private String request(String path) throws IOException, ServiceException {
        String userName = "dbwind.liu";
        String password = "haha3.0//";
        Map<String, String> header = new HashMap<>();
        String up = userName + ":" + password;
        header.put("Authorization", "Basic " + Base64.getEncoder().encodeToString(up.getBytes(StandardCharsets.UTF_8)));
        String url = HOST + path;
        ResponseVo response = HttpDemo.httpRequest(url, null, "GET", header, 5_000, 10_000);
        if (response.isHttpStatus2XX()) {
            return response.getContent();
        }
        throw new ServiceException(response.toString());
    }
}
